package com.dodo.blog.ui.component;

import com.dodo.blog.RequestCycle;
import com.dodo.blog.ui.component.container.Container;
import com.dodo.blog.ui.message.FieldMessage;
import com.dodo.blog.ui.message.MessageLevel;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @author <a href="mailto:pohorelec@comvai.com">Jozef Pohorelec</a>
 */
public abstract class HtmlComponent
        implements Component
{
    private static final long serialVersionUID = 1L;

    public enum Tag
    {
        SCRIPT( "script" ),
        LINK( "link" ),
        META( "meta" ),
        TITLE( "title" ),

        HTML( "html" ),
        HEAD( "head" ),
        BODY( "body" ),
        DIV( "div" ),
        HEADER( "header" ),
        FOOTER( "footer" ),
        NAV( "nav" ),
        ASIDE( "aside" ),
        SECTION( "section" ),
        FIELDSET( "fieldset" ),
        FORM( "form" ),
        PARAGRAPH( "p" ),
        H1( "h1" ),
        H2( "h2" ),
        H3( "h3" ),
        H4( "h4" ),
        H5( "h5" ),
        H6( "h6" ),
        TABLE( "table" ),
        TR( "tr" ),
        TH( "th" ),
        TD( "td" ),
        UL( "ul" ),
        LI( "li" ),

        LABEL( "label" ),
        SPAN( "span" ),
        INPUT( "input" ),
        BUTTON( "button" ),
        ANCHOR( "a" ),
        TEXTAREA( "textarea" ),
        SELECT( "select" ),
        OPTION( "option" ),
        BR( "br" );

        String name;

        Tag( String name )
        {
            this.name = name;
        }

        public String getName()
        {
            return name;
        }
    }

    public enum Attribute
    {
        ID( "id" ),
        NAME( "name" ),
        CLASS( "class" ),
        TYPE( "type" ),
        VALUE( "value" ),
        READONLY( "readonly" ),
        DISABLED( "disabled" ),
        PLACEHOLDER( "placeholder" ),
        CHECKED( "checked" ),
        HREF( "href" ),
        SELECTED( "selected" ),
        METHOD( "method" ),
        ACTION( "action" ),
        MODEL( "model" ),
        AUTOFOCUS( "autofocus" ),
        STYLE( "style" );

        String name;

        Attribute( String name )
        {
            this.name = name;
        }

        public String getName()
        {
            return name;
        }
    }

    public enum Type
    {
        INLINE,
        BLOCK
    }

    private Tag tag;

    private Type type;

    private Map<String, String> attributeMap = new HashMap<String, String>();

    public HtmlComponent( Tag tag, Type type )
    {
        this.tag = tag;
        this.type = type;
    }

    public void setAttribute( Attribute attribute, String value )
    {
        if ( !StringUtils.isBlank( value ) )
        {
            setAttribute( attribute.getName(), value );
        }
    }

    public void setAttribute( Attribute attribute )
    {
        setAttribute( attribute.getName() );
    }

    public void setAttribute( String attribute )
    {
        setAttribute( attribute, attribute );
    }

    public void setAttribute( String name, String value )
    {
        attributeMap.put( name, value );
    }

    public void removeAttribute( Attribute attribute )
    {
        removeAttribute( attribute.getName() );
    }

    public void removeAttribute( String attribute )
    {
        attributeMap.remove( attribute );
    }

    public String getAttribute( Attribute attribute )
    {
        return getAttribute( attribute.getName() );
    }

    public String getAttribute( String name )
    {
        return attributeMap.get( name );
    }

    public void setId( String id )
    {
        setAttribute( Attribute.ID, id );
    }

    public String getId()
    {
        return getAttribute( Attribute.ID );
    }

    public void setName( String name )
    {
        setAttribute( Attribute.NAME, name );
    }

    public String getName()
    {
        return getAttribute( Attribute.NAME );
    }

    public void setClassName( String className )
    {
        setAttribute( Attribute.CLASS, className );
    }

    public void addClassName( String className )
    {
        String clazz = getAttribute( Attribute.CLASS );

        if ( clazz == null )
        {
            setAttribute( Attribute.CLASS, className );
        }
        else
        {
            String[] split = clazz.split( " " );
            for ( String s : split )
            {
                if ( s.equals( className ) )
                {
                    return;
                }
            }

            setAttribute( Attribute.CLASS, getAttribute( Attribute.CLASS ) + " " + className );
        }
    }

    public HttpServletRequest getRequest()
    {
        return RequestCycle.get().getRequest();
    }

    public HttpServletResponse getResponse()
    {
        return RequestCycle.get().getResponse();
    }

    @Override
    public StringBuilder render()
    {
        StringBuilder sb = new StringBuilder();

        sb.append( "<" );
        sb.append( tag.getName() );

        for ( Map.Entry<String, String> attr : attributeMap.entrySet() )
        {
            sb.append( " " );
            sb.append( attr.getKey() );
            sb.append( "='" );
            sb.append( attr.getValue() );
            sb.append( "'" );
        }

        sb.append( type == Type.INLINE ? "/>" : ">" );

        if ( this instanceof Container )
        {
            Container container = ( Container ) this;
            for ( Component c : container.getComps() )
            {
                sb.append( c.render() );
            }

            if ( container.getInnerHtml() != null )
            {
                sb.append( container.getInnerHtml() );
            }
        }

        if ( type == Type.BLOCK )
        {
            sb.append( "</" );
            sb.append( tag.getName() );
            sb.append( ">" );
        }

        return sb;
    }

    public void setStyle( String style )
    {
        setAttribute( Attribute.STYLE, style );
    }

    public void info( String message )
    {
        RequestCycle.get().addMessage( new FieldMessage( getId(), message, MessageLevel.INFO ) );
    }

    public void warn( String message )
    {
        RequestCycle.get().addMessage( new FieldMessage( getId(), message, MessageLevel.WARN ) );
    }

    public void error( String message )
    {
        RequestCycle.get().addMessage( new FieldMessage( getId(), message, MessageLevel.ERROR ) );
    }
}
